/**
 * 20220121：finalized by jordia
 */
import Vec3 from "../../common/vec3";
import CONSTANT from "../../constant";
import Method from "../../common/method";

/**
 * 扩展多边形三角面
 */
export default class EpaTriangle {
    constructor() {
        this.id = ++CONSTANT.EPA_TRIANGLE_COUNT;
        this._next = null;
        this._prev = null;
        this._normal = new Vec3();
        this._distanceSq = 0;
        this._tmpDfsId = 0;
        this._tmpDfsVisible = false;
        this._vertices = new Array(3);
        this._adjacentTriangles = new Array(3);
        this._adjacentPairIndex = new Int8Array(3);
        this.tmp = new Vec3();
        this._nextIndex=Method.setXYZ(new Int8Array(3),1,2,0,0);
        this._ev0=new Float64Array(3);
        this._ev1=new Float64Array(3);
        this._ev2=new Float64Array(3);
        this._ev3=new Float64Array(3);
        this._ev4=new Float64Array(3);
        this._ev5=new Float64Array(3);
        this._ev6=new Float64Array(3);
        this._ev7=new Float64Array(3);
        this._ev8=new Float64Array(3);
        this._ev9=new Float64Array(3);
        this._ev10=new Float64Array(3);
        this._evv0=new Float64Array(3);
        this._evv1=new Float64Array(3);
        this._evv2=new Float64Array(3);
    }
    _getMiv(vec1,vec2,out){
        let v1=Method.copyElements(vec1,this._evv0,0,0,3);
        let v2=Method.copyElements(vec2,this._evv1,0,0,3);
        let v12=Method.subArray(v2,v1,this._evv2,0,0,0,3);
        let t=Method.multiplyArray(v12,v1,0,0,3);
        t = -t / Method.multiplyArray(v12,v12,0,0,3);
        if(t < 0) {
            Method.copyElements(v1,out,0,0,3);
        } else if(t > 1) {
            Method.copyElements(v2,out,0,0,3);
        } else {
            Method.scaleArray(v12,t,v12,0,0,3);
            Method.addArray(v1,v12,out,0,0,0,3);
        }
        return Method.multiplyArray(out,out,0,0,3);
    }
    init(vertex1,vertex2,vertex3,center,autoCheck) {
        if(autoCheck == null) {
            autoCheck = false;
        }
        let vertices=this._vertices;
        let v1=Method.copyElements(vertex1.v.elements,this._ev0,0,0,3);
        let v2=Method.copyElements(vertex2.v.elements,this._ev1,0,0,3);
        let v3=Method.copyElements(vertex3.v.elements,this._ev2,0,0,3);
        let vc=Method.copyElements(center.elements,this._ev3,0,0,3);
        let v12=Method.subArray(v2,v1,this._ev4,0,0,0,3);
        let v13=Method.subArray(v3,v1,this._ev5,0,0,0,3);
        let vc1=Method.subArray(v1,vc,this._ev6,0,0,0,3);
        let inr=Method.crossVectors(v12[0],v12[1],v12[2],v13[0],v13[1],v13[2],this._ev7,0);
        let inverted = false;
        if(Method.multiplyArray(vc1,inr,0,0,3) < 0) {
            if(autoCheck) {
                let tmp = vertex2;
                vertex2 = vertex3;
                vertex3 = tmp;
                inr[0] *= -1;inr[1] *= -1;inr[2] *= -1;
            } else {
                inverted = true;
            }
        }
        Method.setXYZ(vertices,vertex1,vertex2,vertex3,0);
        Method.copyElements(inr,this._normal.elements,0,0,3);
        let vec1 = vertex1.v.elements;
        let vec2 = vertex2.v.elements;
        let vec3 = vertex3.v.elements;
        let out = this.tmp.elements;
        let v11=Method.copyElements(vec1,this._ev0,0,0,3);
        let v21=Method.copyElements(vec2,this._ev1,0,0,3);
        let v31=Method.copyElements(vec3,this._ev2,0,0,3);
        let v121=Method.subArray(v21,v11,this._ev3,0,0,0,3);
        let v23=Method.subArray(v31,v21,this._ev4,0,0,0,3);
        let v311=Method.subArray(v11,v31,this._ev5,0,0,0,3);
        let n=Method.crossVectors(v121[0],v121[1],v121[2],v23[0],v23[1],v23[2],this._ev6,0);
        let n12=Method.crossVectors(v121[0],v121[1],v121[2],n[0],n[1],n[2],this._ev7,0);
        let n23=Method.crossVectors(v23[0],v23[1],v23[2],n[0],n[1],n[2],this._ev8,0);
        let n31=Method.crossVectors(v311[0],v311[1],v311[2],n[0],n[1],n[2],this._ev9,0);
        let mind = -1;
        let miv=Method.setXYZ(this._ev10,0,0,0,0);
        if(Method.multiplyArray(v11,n12,0,0,3) < 0) {
            mind=this._getMiv(vec1,vec2,out);
            Method.copyElements(out,miv,0,0,3);
        }
        if(Method.multiplyArray(v21,n23,0,0,3) < 0) {
            let d=this._getMiv(vec2,vec3,out);
            if(mind < 0 || d < mind) {
                mind = d;
                Method.copyElements(out,miv,0,0,3);
            }
        }
        if(Method.multiplyArray(v31,n31,0,0,3) < 0) {
            let d=this._getMiv(vec1,vec3,out);
            if(mind < 0 || d < mind) {
                mind = d;
                Method.copyElements(out,miv,0,0,3);
            }
        }
        if(mind > 0) {
            Method.copyElements(miv,out,0,0,3);
        } else {
            let l=Method.multiplyArray(n,n,0,0,3);
            if(l > 0) l = 1 / Math.sqrt(l);
            Method.scaleArray(n,l,n,0,0,3);
            let l2 = Method.multiplyArray(n,n,0,0,3);
            l2 = Method.multiplyArray(v11,n,0,0,3) / l2;
            Method.scaleArray(n,l2,miv,0,0,3);
            Method.copyElements(miv,out,0,0,3);
        }
        let tmp = this.tmp.elements;
        this._distanceSq = Method.multiplyArray(tmp,tmp,0,0,3);
        Method.fillValue(this._adjacentTriangles,0,2,null);
        Method.fillValue(this._adjacentPairIndex,0,2,-1);
        return !inverted;
    }
    setAdjacentTriangle(triangle) {
        let hv=this._vertices,hat=this._adjacentTriangles,hai=this._adjacentPairIndex,ni=this._nextIndex;
        let tv=triangle._vertices,tat=triangle._adjacentTriangles,tai=triangle._adjacentPairIndex;
        let count = 0;
        if(hv[0] === tv[ni[0]] && hv[ni[0]] === tv[0]) {
            hat[0] = triangle;
            hai[0] = 0;
            tat[0] = this;
            tai[0] = 0;
            count = 1;
        }
        if(hv[0] === tv[ni[1]] && hv[ni[0]] === tv[1]) {
            hat[0] = triangle;
            hai[0] = 1;
            tat[1] = this;
            tai[1] = 0;
            ++count;
        }
        if(hv[0] === tv[ni[2]] && hv[ni[0]] === tv[2]) {
            hat[0] = triangle;
            hai[0] = 2;
            tat[2] = this;
            tai[2] = 0;
            ++count;
        }
        if(hv[1] === tv[ni[0]] && hv[ni[1]] === tv[0]) {
            hat[1] = triangle;
            hai[1] = 0;
            tat[0] = this;
            tai[0] = 1;
            ++count;
        }
        if(hv[1] === tv[ni[1]] && hv[ni[1]] === tv[1]) {
            hat[1] = triangle;
            hai[1] = 1;
            tat[1] = this;
            tai[1] = 1;
            ++count;
        }
        if(hv[1] === tv[ni[2]] && hv[ni[1]] === tv[2]) {
            hat[1] = triangle;
            hai[1] = 2;
            tat[2] = this;
            tai[2] = 1;
            ++count;
        }
        if(hv[2] === tv[ni[0]] && hv[ni[2]] === tv[0]) {
            hat[2] = triangle;
            hai[2] = 0;
            tat[0] = this;
            tai[0] = 2;
            ++count;
        }
        if(hv[2] === tv[ni[1]] && hv[ni[2]] === tv[1]) {
            hat[2] = triangle;
            hai[2] = 1;
            tat[1] = this;
            tai[1] = 2;
            ++count;
        }
        if(hv[2] === tv[ni[2]] && hv[ni[2]] === tv[2]) {
            hat[2] = triangle;
            hai[2] = 2;
            tat[2] = this;
            tai[2] = 2;
            ++count;
        }
        return count===1;
    }
    removeAdjacentTriangles() {
        let adt=this._adjacentTriangles,adi=this._adjacentPairIndex;
        let triangle = adt[0];
        if(triangle != null) {
            let pairIndex = adi[0];
            triangle._adjacentTriangles[pairIndex] = null;
            triangle._adjacentPairIndex[pairIndex] = -1;
            adt[0] = null;
            adi[0] = -1;
        }
        let triangle1 = adt[1];
        if(triangle1 != null) {
            let pairIndex = adi[1];
            triangle1._adjacentTriangles[pairIndex] = null;
            triangle1._adjacentPairIndex[pairIndex] = -1;
            adt[1] = null;
            adi[1] = -1;
        }
        let triangle2 = adt[2];
        if(triangle2 != null) {
            let pairIndex = adi[2];
            triangle2._adjacentTriangles[pairIndex] = null;
            triangle2._adjacentPairIndex[pairIndex] = -1;
            adt[2] = null;
            adi[2] = -1;
        }
    }
    removeReferences() {
        this._next = null;
        this._prev = null;
        this._tmpDfsId = 0;
        this._tmpDfsVisible = false;
        this._distanceSq = 0;
        Method.fillValue(this._vertices,0,2,null);
        Method.fillValue(this._adjacentTriangles,0,2,null);
        Method.fillValue(this._adjacentPairIndex,0,2,0);
    }
    dump() {}
}